﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
using AvaloniaApplicationDemo.IServices;
using AvaloniaApplicationDemo.Models;
using AvaloniaApplicationDemo.Util;
using AvaloniaApplicationDemo.ViewModels;
using Modbus.Device;

namespace AvaloniaApplicationDemo.Services;

public class ModbusManager : IModbusManager
{
    // 状态变更事件：连接状态、数据更新、错误等
    public event EventHandler<ModbusStatusEventsAgrs>? StatusChanged;


    // // 新增：寄存器地址与别名的映射字典
    private Dictionary<ushort, string> _registerMappings = new();


    // 数据解析逻辑可通过外部注入（默认使用内置解析）
    public Func<ushort[], int, ModbusDeviceData> DataParser { get; set; }

    public ModbusManager(DeviceModel deviceModel, SlaveInfo slaveInfo)
    {
        // 默认解析逻辑
        DataParser = (rawData, length) =>
        {
            if (_registerMappings.Count > 0)
            {
                // 使用CSV映射进行动态解析
                return ParseDataWithMappings(rawData, deviceModel, slaveInfo);
            }
            else
            {
                // 使用默认解析
                AppLogger.Debug("使用内置解析");
                var modbusDeviceData = new ModbusDeviceData();
                ParseDeviceData(rawData, modbusDeviceData, length);
                return modbusDeviceData;
            }
        };
     
    }

    /// <summary>
    /// 使用CSV映射关系解析数据
    /// </summary>
    private ModbusDeviceData ParseDataWithMappings(ushort[] rawData, DeviceModel deviceModel, SlaveInfo slaveInfo)
    {
        var deviceData = new ModbusDeviceData();
        // 如果有映射关系，则使用映射关系解析
        if (deviceModel.RegisterMappings.Count > 0)
        {
            foreach (var mapping in deviceModel.RegisterMappings)
            {
                int registerAddr = mapping.Key;
                var alias = mapping.Value;

                // 计算在rawData中的索引位置
                var index = registerAddr - slaveInfo.StartAddress;

                if (index >= 0 && index < rawData.Length)
                    // 根据别名设置对应属性
                    switch (alias)
                    {
                        case "电压设置":
                            deviceData.VoltageSetting = rawData[index];
                            break;
                        case "电流设置":
                            deviceData.CurrentSetting = rawData[index];
                            break;
                        case "输出电压":
                            deviceData.OutputVoltage = rawData[index];
                            break;
                        case "输出电流":
                            deviceData.OutputCurrent = rawData[index];
                            break;
                        case "输出功率":
                            deviceData.OutputPower = rawData[index];
                            break;
                        case "输入电压":
                            deviceData.InputVoltage = rawData[index];
                            break;
                        // 处理双字数据（高16位）
                        case "输出瓦时高16位":
                            if (index + 1 < rawData.Length)
                                deviceData.OutputWH = (uint)((rawData[index] << 16) | rawData[index - 1]);
                            break;
                        case "输出安时高16位":
                            if (index + 1 < rawData.Length)
                                deviceData.OutputAH = (uint)((rawData[index] << 16) | rawData[index - 1]);
                            break;
                        case "输出小时":
                            deviceData.OutputHours = rawData[index];
                            break;
                        case "输出分钟":
                            deviceData.OutputMinutes = rawData[index];
                            break;
                        case "输出秒":
                            deviceData.OutputSeconds = rawData[index];
                            break;
                        case "内部温度":
                            deviceData.InternalTemperature = rawData[index];
                            break;
                        case "外部温度":
                            deviceData.ExternalTemperature = rawData[index];
                            break;
                        case "内部温度校正":
                            deviceData.InternalTempCorrection = rawData[index];
                            break;
                        case "外部温度校正":
                            deviceData.ExternalTempCorrection = rawData[index];
                            break;
                        case "温度符号":
                            deviceData.TemperatureSign = rawData[index];
                            break;
                        case "按键锁":
                            deviceData.KeyLock = rawData[index];
                            break;
                        case "保护状态":
                            deviceData.ProtectionStatus = rawData[index];
                            break;
                        case "CC_CV_状态":
                            deviceData.CC_CV_Status = rawData[index];
                            break;
                        case "输出开关状态":
                            deviceData.OutputSwitchStatus = rawData[index];
                            break;
                        case "背光等级":
                            deviceData.BacklightLevel = rawData[index];
                            break;
                        case "屏幕超时":
                            deviceData.ScreenTimeout = rawData[index];
                            break;
                        case "产品型号":
                            deviceData.ProductModel = rawData[index];
                            break;
                        case "固件版本":
                            deviceData.FirmwareVersion = rawData[index];
                            break;
                        case "从站地址":
                            deviceData.SlaveAddress = rawData[index];
                            break;
                        case "波特率代码":
                            deviceData.BaudRateCode = rawData[index];
                            break;
                        case "蜂鸣器开关":
                            deviceData.BuzzerSwitch = rawData[index];
                            break;
                        case "快速数据组":
                            deviceData.QuickDataGroup = rawData[index];
                            break;
                    }
            }
        }
        // 如果没有映射关系，使用默认解析
        else
        {
            AppLogger.Warning("没有为设备 {0} 导入寄存器映射关系", deviceModel.DeviceName);
            ParseDeviceData(rawData, deviceData, rawData.Length);
        }

        return deviceData;
    }

    /// <summary>
    /// 读取设备数据点并解析
    /// </summary>
    /// <param name="slaveInfo">设备从站信息</param>
    /// <param name="deviceModel">设备信息</param>
    /// <returns>解析后的数据模型ModbusDeviceData</returns>
    public async Task ReadDataPointAsync(SlaveInfo slaveInfo, DeviceModel deviceModel)
    {
        var isConnected = await ConnectAsync(slaveInfo, deviceModel, true);
        if (isConnected)
            try
            {
                var result =
                    await deviceModel.Master.ReadHoldingRegistersAsync(slaveInfo.SlaveId, slaveInfo.StartAddress,
                        slaveInfo.Quantity);
                if (result.Length < slaveInfo.Quantity)
                {
                    StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(true, "数据长度不足"));
                    return;
                }

                // 使用注入的解析逻辑处理数据
                var deviceData = DataParser(result, slaveInfo.Quantity);
                deviceData.IsValid = true;
                deviceData.Timestamp = DateTime.Now;

                // 触发数据更新事件
                StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(true, "TimerData", deviceData: deviceData));
            }
            catch (Exception e)
            {
                AppLogger.Error(e, "Read Data Point Failed");
                StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(false, "读取数据点时发生异常！"));
            }
            finally
            {
                deviceModel.TcpClient?.Close();
                deviceModel.Master?.Dispose();
                deviceModel.TcpClient?.Dispose();
            }
        else
            StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(false, "设备未连接"));
    }

    #region 设备连接、断开、数据读取、数据写入

    /// <summary>
    /// 连接设备
    /// </summary>
    /// <param name="slaveInfo"></param>
    /// <param name="deviceModel"></param>
    /// <param name="isAutoTest"></param>
    /// <returns></returns>
    public async Task<bool> ConnectAsync(SlaveInfo slaveInfo, DeviceModel deviceModel, bool isAutoTest = false)
    {
        deviceModel.TcpClient = new TcpClient();
        deviceModel.TcpClient.ReceiveTimeout = slaveInfo.TcpTimeout;
        await deviceModel.TcpClient.ConnectAsync(slaveInfo.IpServer, slaveInfo.PortServer);

        var tcpModbusMaster = ModbusSerialMaster.CreateRtu(deviceModel.TcpClient);
        if (tcpModbusMaster == null) return false;
        deviceModel.Master = tcpModbusMaster;
        deviceModel.IsConnected = true;
        if (!isAutoTest)
        {
            StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(true, "连接成功！"));
            // 连接成功后，默认上电关闭输出
            await deviceModel.Master.WriteSingleRegisterAsync(slaveInfo.SlaveId, 18, 0);
        }

        return true;
    }

    /// <summary>
    /// 断开连接
    /// </summary>
    /// <param name="deviceModel"></param>
    /// <returns></returns>
    public Task<bool> DisconnectAsync(DeviceModel deviceModel)
    {
        try
        {
            deviceModel.Master?.Dispose(); // 释放 Modbus 主站资源
            deviceModel.TcpClient?.Close(); // 关闭 TCP 连接
            deviceModel.TcpClient?.Dispose(); // 释放 TCP 客户端资源

            deviceModel.Master = null;
            deviceModel.TcpClient = null;
            deviceModel.IsConnected = false;
            StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(false, "已断开连接！"));
            return Task.FromResult(true);
        }
        catch (Exception ex)
        {
            AppLogger.Error(ex, "断开连接时发生异常");
            StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(false, "断开连接时发生异常！"));
            return Task.FromResult(false);
        }
    }


    /// <summary>
    /// 写单个保持寄存器
    /// </summary>
    /// <param name="slaveInfo">设备从站信息</param>
    /// <param name="deviceModel">设备信息</param>
    /// <param name="addrRegister">寄存器地址</param>
    /// <param name="valueRegister">寄存器值</param>
    /// <returns></returns>
    public async Task<bool> SaveSettingsDataAsync(SlaveInfo slaveInfo, DeviceModel deviceModel, ushort addrRegister,
        ushort valueRegister)
    {
        var tempTcpClient = deviceModel.TcpClient;
        var tempMaster = deviceModel.Master;
        try
        {
            tempTcpClient = new TcpClient();
            tempTcpClient.ReceiveTimeout = slaveInfo.TcpTimeout;
            await tempTcpClient.ConnectAsync(slaveInfo.IpServer, slaveInfo.PortServer);
            tempMaster = ModbusSerialMaster.CreateRtu(tempTcpClient);
            if (tempMaster == null)
            {
                StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(false, "写入时创建ModbusMaster对象失败！"));
                return false;
            }

            await tempMaster.WriteSingleRegisterAsync(slaveInfo.SlaveId, addrRegister, valueRegister);

            switch (addrRegister)
            {
                case 18:
                    StatusChanged?.Invoke(this,
                        valueRegister == 0
                            ? new ModbusStatusEventsAgrs(true, $"停止输出--成功")
                            : new ModbusStatusEventsAgrs(true, $"启动输出--成功"));
                    break;
                case 0:
                    StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(true, $"设置输出电压:{valueRegister}--成功"));
                    break;
                case 1:
                    StatusChanged?.Invoke(this, new ModbusStatusEventsAgrs(true, $"设置输出电流:{valueRegister}--成功"));
                    break;
            }

            return true;
        }
        catch (Exception e)
        {
            AppLogger.Error(e, "Save Settings Data Exception");
            StatusChanged?.Invoke(this,
                new ModbusStatusEventsAgrs(false, "保存地址：" + addrRegister + " 值为：" + valueRegister + "设置数据时发生异常！"));
            return false;
        }
        finally
        {
            tempTcpClient?.Close();
            tempMaster?.Dispose();
            tempTcpClient?.Dispose();
        }
    }

    #endregion

    /// <summary>
    /// 解析数据
    /// </summary>
    /// <param name="rawData">原始数据</param>
    /// <param name="deviceData">设备数据</param>
    /// <param name="rawLength">原始数据长度</param>
    private ModbusDeviceData ParseDeviceData(ushort[] rawData, ModbusDeviceData deviceData, int rawLength)
    {
        if (rawData.Length < rawLength)
        {
            AppLogger.Information("数据长度不足，原始数据长度：{0}，实际数据长度：{1}", rawLength, rawData.Length);
            return deviceData;
        }

        //调试输出返回的数据
        // Console.WriteLine($"Raw data length: {rawData.Length}");
        // for(int i = 0; i < Math.Min(rawData.Length, 10); i++)
        // {
        //     Console.WriteLine($"Index {i}: {rawData[i]}");
        // }

        // 基本设置参数 (索引 0-1)
        deviceData.VoltageSetting = rawData[0];
        deviceData.CurrentSetting = rawData[1];

        // 输出参数 (索引 2-4)
        deviceData.OutputVoltage = rawData[2];
        deviceData.OutputCurrent = rawData[3];
        deviceData.OutputPower = rawData[4];

        // 输入参数 (索引 5)
        deviceData.InputVoltage = rawData[5];

        // 累计数据 (索引 6-9)
        deviceData.OutputAH = (uint)((rawData[7] << 16) | rawData[6]); // 低16位+高16位
        deviceData.OutputWH = (uint)((rawData[9] << 16) | rawData[8]); // 低16位+高16位

        // 时间参数 (索引 10-12)
        deviceData.OutputHours = rawData[10];
        deviceData.OutputMinutes = rawData[11];
        deviceData.OutputSeconds = rawData[12];

        // 温度参数 (索引 13-14)
        deviceData.InternalTemperature = rawData[13];
        deviceData.ExternalTemperature = rawData[14];

        // 状态参数 (索引 15-19)
        deviceData.KeyLock = rawData[15];
        deviceData.ProtectionStatus = rawData[16];
        deviceData.CC_CV_Status = rawData[17];
        deviceData.OutputSwitchStatus = rawData[18];
        deviceData.TemperatureSign = rawData[19];

        // 显示设置 (索引 20-21)
        deviceData.BacklightLevel = rawData[20];
        deviceData.ScreenTimeout = rawData[21];

        // 设备信息 (索引 22-23)
        deviceData.ProductModel = rawData[22];
        deviceData.FirmwareVersion = rawData[23];

        // 通讯设置 (索引 24-25)
        deviceData.SlaveAddress = rawData[24];
        deviceData.BaudRateCode = rawData[25];

        // 校准参数 (索引 26-27)
        deviceData.InternalTempCorrection = rawData[26];
        deviceData.ExternalTempCorrection = rawData[27];

        // 其他设置 (索引 28-29)
        deviceData.BuzzerSwitch = rawData[28];
        deviceData.QuickDataGroup = rawData[29];

        deviceData.Timestamp = DateTime.Now;
        return deviceData;
    }
}